#include <algorithm>
#include <cstdio>

typedef long long ll;
const int N = 100005, mod = 998244353, bit = 31;
int n, m, readonly[N], w[N];

inline int qpow(ll base, int exp) {
  ll res = 1;
  while (exp) {
    if (exp & 1) res = res * base % mod;
    exp >>= 1;
    base = base * base % mod;
  }
  return res;
}

const int inv = qpow(2, mod - 2);

struct Result {
  int x, y;
  Result(int x, int y) : x(x), y(y) {}
  inline void operator+=(const Result &rhs) { x += rhs.x, y += rhs.y; }
};

struct SegmentTree {
  struct Node {
    int writable, cnt, siz;
    bool tag;
  } tr[N << 2];

  inline void pushup(int x) {
    tr[x].cnt = tr[x << 1].cnt + tr[x << 1 | 1].cnt;
    tr[x].writable = tr[x << 1].writable + tr[x << 1 | 1].writable;
  }

  inline void pushdown(int x, int l, int r) {
    static int ls, rs, mid;
    if (tr[x].tag) {
      ls = x << 1, rs = x << 1 | 1, mid = (l + r) >> 1;
      tr[ls].tag ^= 1, tr[rs].tag ^= 1;
      tr[ls].writable = tr[ls].siz - tr[ls].writable;
      tr[rs].writable = tr[rs].siz - tr[rs].writable;
      tr[ls].cnt = mid - l + 1 - tr[ls].cnt;
      tr[rs].cnt = r - mid - tr[rs].cnt;
      tr[x].tag = 0;
    }
  }

  inline void build(int x, int l, int r, int k) {
    if (l == r) {
      tr[x].siz = !readonly[l];
      tr[x].cnt = w[l] >> k & 1;
      tr[x].writable = tr[x].cnt & !readonly[l];
      return;
    }
    int mid = (l + r) >> 1;
    build(x << 1, l, mid, k);
    build(x << 1 | 1, mid + 1, r, k);
    pushup(x);
    tr[x].siz = tr[x << 1].siz + tr[x << 1 | 1].siz;
  }

  Result query(int x, int l, int r, int L, int R) {
    if (L <= l && r <= R) { return Result(tr[x].cnt, tr[x].writable); }
    int mid = (l + r) >> 1;
    Result res(0, 0);
    pushdown(x, l, r);
    if (L <= mid) res += query(x << 1, l, mid, L, R);
    if (mid < R) res += query(x << 1 | 1, mid + 1, r, L, R);
    return res;
  }

  void modify(int x, int l, int r, int L, int R) {
    if (L <= l && r <= R) {
      tr[x].tag ^= 1;
      tr[x].writable = tr[x].siz - tr[x].writable;
      tr[x].cnt = r - l + 1 - tr[x].cnt;
      return;
    }
    int mid = (l + r) >> 1;
    pushdown(x, l, r);
    if (L <= mid) modify(x << 1, l, mid, L, R);
    if (mid < R) modify(x << 1 | 1, mid + 1, r, L, R);
    pushup(x);
  }
} seg[bit];

inline ll calc(ll x, ll step) {
  return 1ll * (x + x + step) % mod * (step + 1) % mod * inv % mod;
}

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("testdata.in", "r", stdin);
  freopen("testdata.out", "w", stdout);
#else
  freopen("oldgardener.in", "r", stdin);
  freopen("oldgardener.out", "w", stdout);
#endif
#endif

  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i) { scanf("%d", &readonly[i]); }
  for (int i = 1; i <= n; ++i) { scanf("%d", &w[i]); }
  for (int i = 0; i < bit; ++i) seg[i].build(1, 1, n, i);
  for (int i = 1, opt, l, r, y; i <= m; ++i) {
    scanf("%d%d%d", &opt, &l, &r);
    if (opt == 1) {
      scanf("%d", &y);
      for (int i = 0; i < bit; ++i)
        if (y >> i & 1) seg[i].modify(1, 1, n, l, r);
    } else {
      ll ans = 0;
      int sig = 0;
      for (int i = bit - 1; ~i; --i) {
        Result res = seg[i].query(1, 1, n, l, r);
        if (res.y) {
          ans += calc(sig | ((int)(!(res.x & 1)) << i), (1 << i) - 1);
          if (ans >= mod) ans -= mod;
        }
        if (res.x & 1) sig |= 1 << i;
      }
      printf("%lld\n", ans);
    }
  }
  return 0;
}